#include "stdafx.h"
#include <winsock2.h>  
#include <windows.h>
#include <process.h>
#include "RtmpRecord.h"
#include "remuxing.h"

bool g_bExit = false;

BOOL CALLBACK CosonleHandler(DWORD ev)
{
    BOOL bRet = FALSE;
    switch (ev)
    {
    case CTRL_C_EVENT:
    case CTRL_BREAK_EVENT:
    case CTRL_CLOSE_EVENT:
    case CTRL_LOGOFF_EVENT:
    case CTRL_SHUTDOWN_EVENT:
        printf("exiting ...\n");
        g_bExit = true;
        bRet = TRUE;

        RtmpRecordThreadPool::Instance().NoticeAll();
        RtmpRecordThreadPool::Instance().Join();
        //system("pause");
        break;
    default:
        break;
    }
    return bRet;
}


int InitSockets()
{
#ifdef WIN32
    WORD version;
    WSADATA wsaData;
    version = MAKEWORD(1, 1);
    return (WSAStartup(version, &wsaData) == 0);
#endif
}

void CleanupSockets()
{
#ifdef WIN32
    WSACleanup();
#endif
}

unsigned __stdcall ThreadProc(LPVOID lpParam)
{
    RtmpRecordThread* pThread = (RtmpRecordThread*)lpParam;
    return pThread->Run();
}

bool RtmpRecordThread::SetFlvFilename()
{
    bool bSucced = false;

    mtx.lock();
    int date = m_inning / 10000;
    if (date != m_lastInning / 10000)
    {
        char dir[256] = { 0 };
        sprintf(dir, "%s%d\\", m_dir, date);

        if (!IsDirExist(dir))
        {
            createDirectory(dir);
        }
    }

    if (m_inning > 0)
    {
        bSucced = true;
        memset(flvfilename, 0, sizeof(flvfilename));
        sprintf(flvfilename, "%s%d\\%lld.flv", m_dir, date, m_inning);
    }

    mtx.unlock();

    return bSucced;
}


void RtmpRecordThread::SetInning(long long inning)
{
    bool notify = false;
    mtx.lock();
    if (m_inning != inning)
    {
        m_lastInning = m_inning;
        m_inning = inning;

        notify = true;
    }
    mtx.unlock();

    if (notify)
    {
        SetStartEvent();
    }
}


bool RtmpRecordThread::IsWrting()
{
    DWORD dwWaitResult = WaitForSingleObject(
        m_hWriteEvent, // event handle
        0);    // indefinite wait

    bool bWrting = false;
    switch (dwWaitResult)
    {
        // Event object was signaled
    case WAIT_OBJECT_0:
        bWrting = true;
        break;
    case WAIT_TIMEOUT:
        break;
        // An error occurred
    default:
        printf("Wait error (%d)\n", GetLastError());
        break;
    }
    return bWrting;
}

void RtmpRecordThread::CreateEvents(void)
{
    // Create a manual-reset event object. The write thread sets this
    // object to the signaled state when it finishes writing to a 
    // shared buffer. 
    m_hWriteEvent = CreateEvent(
        NULL,               // default security attributes
        TRUE,               // manual-reset event
        FALSE,              // initial state is nonsignaled
        NULL  // object name
        );

    if (m_hWriteEvent == NULL)
    {
        printf("CreateEvent failed (%d)\n", GetLastError());
        return;
    }
    
    m_hStartEvent = CreateEvent(
        NULL,               // default security attributes
        FALSE,               // manual-reset event
        FALSE,              // initial state is nonsignaled
        NULL  // object name
        );

    if (m_hStartEvent == NULL)
    {
        printf("CreateEvent failed (%d)\n", GetLastError());
        return;
    }

    m_hStopEvent = CreateEvent(
        NULL,               // default security attributes
        TRUE,               // manual-reset event
        FALSE,              // initial state is nonsignaled
        NULL  // object name
        );

    if (m_hStopEvent == NULL)
    {
        printf("CreateEvent failed (%d)\n", GetLastError());
        return;
    }
}

void RtmpRecordThread::CreateThreads(void)
{
    unsigned threadID;
    // Create multiple threads to read from the buffer.

    // TODO: More complex scenarios may require use of a parameter
    //   to the thread procedure, such as an event per thread to  
    //   be used for synchronization.
    m_hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, this, 0, &threadID);

    if (m_hThread == NULL)
    {
        printf("CreateThread failed (%d)\n", GetLastError());
        return;
    }
}

void RtmpRecordThread::Join()
{
    DWORD dwWaitResult = WaitForSingleObject(m_hThread, INFINITE);
    switch (dwWaitResult)
    {
        // Event object was signaled
    case WAIT_OBJECT_0:
        break;
        // An error occurred
    default:
        printf("Wait error (%d)\n", GetLastError());
        break;
    }
}

unsigned RtmpRecordThread::Run()
{
    while (!g_bExit)
    {
        DWORD dwWaitResult = WaitForSingleObject(
            m_hStartEvent, // event handle
            INFINITE);    // indefinite wait

        bool bEnd = false;
        switch (dwWaitResult)
        {
            // Event object was signaled
        case WAIT_OBJECT_0:
            break;
        case WAIT_TIMEOUT:
            break;
            // An error occurred
        default:
            printf("Wait error (%d)\n", GetLastError());
            bEnd = true;
            break;
        }

        if (g_bExit)
        {
            break;
        }
        
        SetWriteEvent();
        if (SetFlvFilename())
        {
            //bool failed = RtmpPlayStream(flvfilename, m_rtmpurl, 1, m_hStopEvent);
            //if (failed)
            //{
            //    printf("RtmpPlayStream failed\n");
            //}

            int ret = ffmpeg_remuxing(m_rtmpurl, flvfilename, m_hStopEvent);
            if (ret > 0)
            {
                printf("RtmpPlayStream failed\n");
            }
        }

        dwWaitResult = WaitForSingleObject(
            m_hStopEvent, // event handle
            INFINITE);    // indefinite wait
        switch (dwWaitResult)
        {
            // Event object was signaled
        case WAIT_OBJECT_0:
            break;
        case WAIT_TIMEOUT:
            break;
            // An error occurred
        default:
            printf("Wait error (%d)\n", GetLastError());
            break;
        }

        ResetEvent(m_hStopEvent);
        ResetEvent(m_hWriteEvent);
    }


    printf("Thread %d exiting\n", GetCurrentThreadId());
    return 1;
}